package ru.mirent;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;

import java.time.LocalDateTime;
import java.util.List;

import static org.mockito.Mockito.*;

/**
 * Проброс исключений при вызове метода заглушенного объекта
 */
public class MockitoThrowExceptionTest {

    /**
     * Первый способ записи объявления замоканного объекта с пробросом исключения
     */
    @Test
    void throwExceptionOneTest() {
        // Создание заглушки
        List<String> mockList = mock(List.class);
        // Настройка проброса исключения при вызове метода
        doThrow(new IllegalStateException("Throw Error from Mockito")).when(mockList).size();

        // Вызов тестируемого метода
        IllegalStateException illegalStateException = Assertions.assertThrows(IllegalStateException.class, () -> mockList.size());
        // Проверка соответствия сообщения об ошибке
        Assertions.assertEquals("Throw Error from Mockito", illegalStateException.getMessage());
    }

    /**
     * Второй способ записи объявления замоканного объекта с пробросом исключения, функционально аналогичен первому
     */
    @Test
    void throwExceptionTwoTest() {
        // Создание заглушки
        List<String> mockList = mock(List.class);
        // Настройка проброса исключения при вызове метода
        when(mockList.size()).thenThrow(new IllegalStateException("Throw Error from Mockito"));

        // Вызов тестируемого метода
        IllegalStateException illegalStateException = Assertions.assertThrows(IllegalStateException.class,
                () -> mockList.size());
        // Проверка соответствия сообщения об ошибке
        Assertions.assertEquals("Throw Error from Mockito", illegalStateException.getMessage());
    }

    /**
     * Пример возврата исключения из класса-заглушки mockLocalDateTime.getMinute после выхова статичного метода
     * класса LocalDateTime.now
     */
    @Test
    void anotherExampleCallStaticTest() {
        // Создание заглушки статичного класса
        try (MockedStatic<LocalDateTime> mocked = mockStatic(LocalDateTime.class)) {
            // Создание дополнительной заглушки дополнительного класса
            LocalDateTime mockLocalDateTime = mock(LocalDateTime.class);
            // Настройка проброса исключения при вызове метода дополнительного класса
            when(mockLocalDateTime.getMinute()).thenThrow(new IllegalStateException("Throw Error from Mockito"));
            // Настройка возврата статичным методом дополнительного класса
            mocked.when(LocalDateTime::now).thenReturn(mockLocalDateTime);

            // Вызов статичного метода класса
            LocalDateTime result = LocalDateTime.now();

            // Вызов тестируемого метода
            IllegalStateException illegalStateException = Assertions.assertThrows(IllegalStateException.class,
                    () -> result.getMinute());
            // Проверка соответствия сообщения об ошибке
            Assertions.assertEquals("Throw Error from Mockito", illegalStateException.getMessage());
        }
    }
}
